use crate::cljcell::clj_cell::CljCell;
use crate::built_in_functions::my_clojure_interp::{CljFunc, CljRecur, MyClojureInterp, CljFuncParam, CljFuncParamList, MyCljFunc, MyFuncHs, MyCljRecur};
use crate::built_in_functions::util::my_util;
use crate::built_in_functions::my_funs::MyFunctions;
use std::collections::HashMap;
use std::fmt;
use std::rc::Rc;
use std::cell::RefCell;

#[derive(Debug)]
pub struct MyCljFuncWraps {
    pub ptr: *mut MyCljFunc,
}

impl MyCljFuncWraps {
    pub fn new() -> Self {
        Self {
            ptr: Box::into_raw(Box::new(MyCljFunc::new1(false))),
        }
    }

    pub fn new1(fs: MyCljFunc) -> Self {
        Self {
            ptr: Box::into_raw(Box::new(fs)),
        }
    }

    pub fn get_is_override(&self) -> &bool {
        unsafe {
            &(*self.ptr).get_is_override()
        }
    }

    pub fn set_is_override(&self, is_override: bool) {
        unsafe {
            (*self.ptr).set_is_override(is_override)
        }
    }

    pub fn get_clj_func(&self) -> &CljFunc {
        unsafe {
            &(*self.ptr).get_clj_func()
        }
    }

    pub fn set_clj_func(&self, clj_func: CljFunc) {
        unsafe {
            (*self.ptr).set_clj_func(clj_func);
        }
    }

    pub fn insert(&self, k: i32, v: CljFunc) {
        unsafe {
            let _ = &(*self.ptr).func_override.insert(k, v);
        }
    }

    pub fn get_func_override(&self) -> &HashMap<i32, CljFunc> {
        unsafe {
            &(*self.ptr).get_func_override()
        }
    }

    pub fn get_func_override_put(&self, i: i32, func: CljFunc) {
        unsafe {
            let _ = &(*self.ptr).func_override.insert(i, func);
        }
    }

    pub fn set_func_override(&mut self, func_override: HashMap<i32, CljFunc>) {
        unsafe {
            (*self.ptr).set_func_override(func_override);
        }
    }

    pub fn get_clj_func_1(&self, psum: i32) -> Option<&CljFunc> {
        unsafe {
            (*self.ptr).get_clj_func_1(psum)
        }
    }

    pub fn get_my_clj_func(&self) -> Box<MyCljFunc> {
        unsafe {
            (*self.ptr).flag = true;
            return Box::from_raw(self.ptr);
        }
    }

}

// 手动实现 Drop 释放内存
impl Drop for MyCljFuncWraps {
    fn drop(&mut self) {
        unsafe {
            if !(*self.ptr).flag {
                let _ = Box::from_raw(self.ptr);
            }
        }
    }
}

pub struct CljFunctions;

impl CljFunctions {

    // pub fn has_rest(lst: &Vec<Rc<CljFuncParam>>) -> bool {
    //     for m in lst {
    //         let p = Rc::as_ptr(&m);
    //         unsafe {
    //             if !(*p).get_rest_param().is_empty() {
    //                 return true;
    //             }
    //         }
    //     }
    //     return false;
    // }

    pub fn has_rest(lst: &Vec<Rc<CljFuncParam>>) -> bool {
        for m in lst {
            if !(*m).get_rest_param().is_empty() {
                return true;
            }
        }
        return false;
    }

    pub fn add_to_func(interp: &MyClojureInterp, my_clj_func: &MyCljFuncWraps, func: CljFunc) -> Result<Option<bool>, String> {
        let my_ptr: &HashMap<i32, CljFunc> = my_clj_func.get_func_override();
        if !my_ptr.contains_key(&(func.get_func_params().len() as i32)) {
            for func1 in my_clj_func.get_func_override().values() {
                if CljFunctions::has_rest(func1.get_func_params()) && func1.get_func_params().len() <= func.get_func_params().len() {
                    return Err(String::from("unexpected 重载中的可变参数函数，中的参数数量不可以小于或等于其它函数的参数数量！"));
                } else if CljFunctions::has_rest(func1.get_func_params()) && CljFunctions::has_rest(func.get_func_params()) {
                    return Err(String::from("unexpected 重载函数不可以有多个可变参数的函数"));
                }
            }
            my_clj_func.insert(func.get_func_params().len() as i32, func);
            return Ok(Some(true));
        }
        // unsafe {
        //     let ptr: *mut HashMap<i32, CljFunc> = (*my_clj_func).get_func_override() as *const HashMap<i32, CljFunc> as *mut HashMap<i32, CljFunc>;
        //     if !(*ptr).contains_key(&(func.get_func_params().len() as i32)) {
        //         for func1 in (*my_clj_func).get_func_override().values() {
        //             if CljFunctions::has_rest(func1.get_func_params()) && func1.get_func_params().len() <= func.get_func_params().len() {
        //                 return Err(String::from("unexpected 重载中的可变参数函数，中的参数数量不可以小于或等于其它函数的参数数量！"));
        //             } else if CljFunctions::has_rest(func1.get_func_params()) && CljFunctions::has_rest(func.get_func_params()) {
        //                 return Err(String::from("unexpected 重载函数不可以有多个可变参数的函数"));
        //             }
        //         }
        //         (*ptr).insert(func.get_func_params().len() as i32, func);
        //         return Ok(Some(true));
        //     }
        // }
        return Err(String::from("unexpected 相同的参数数量不能重载"));
    }

    pub fn add_to_func_0(interp: &MyClojureInterp, my_clj_func: *mut MyCljFunc, func: CljFunc) -> Result<Option<bool>, String> {
        unsafe {
            let ptr: *mut HashMap<i32, CljFunc> = (*my_clj_func).get_func_override() as *const HashMap<i32, CljFunc> as *mut HashMap<i32, CljFunc>;
            if !(*ptr).contains_key(&(func.get_func_params().len() as i32)) {
                for func1 in (*my_clj_func).get_func_override().values() {
                    if CljFunctions::has_rest(func1.get_func_params()) && func1.get_func_params().len() <= func.get_func_params().len() {
                        return Err(String::from("unexpected 重载中的可变参数函数，中的参数数量不可以小于或等于其它函数的参数数量！"));
                    } else if CljFunctions::has_rest(func1.get_func_params()) && CljFunctions::has_rest(func.get_func_params()) {
                        return Err(String::from("unexpected 重载函数不可以有多个可变参数的函数"));
                    }
                }
                (*ptr).insert(func.get_func_params().len() as i32, func);
                return Ok(Some(true));
            }
        }
        return Err(String::from("unexpected 相同的参数数量不能重载"));
    }

    fn to_func_param_list(lst: &Vec<Rc<CljCell>>) -> Result<Vec<Rc<CljFuncParamList>>, String> {
        let mut rs: Vec<Rc<CljFuncParamList>> = Vec::new();
        let mut i = 0;
        while i < lst.len() {
            let c = lst.get(i).unwrap();
            let c1 = c.clone();
            match &*c1 {
                CljCell::Symbol(sy) => {
                    rs.push(Rc::new(CljFuncParamList::new((*sy).to_string())));
                },
                CljCell::Percent(vs) => {
                    let pv = vs.as_ref().unwrap();
                    rs.push(Rc::new(CljFuncParamList::new((*pv).to_string())));
                },
                CljCell::AndClj => {
                    if i == lst.len() - 2 {
                        rs.push(Rc::new(CljFuncParamList::new(lst.get(1 + i).unwrap().to_string())));
                        break;
                    }
                },
                _ => {
                    let mut er = String::from("函数参数错误：");
                    er.push_str(&c.to_string());
                    return Err(er);
                },
            }
            i += 1;
        }

        if rs.len() == 2 {
            return Ok(rs);
        }

        return Err(String::from("函数参数错误：在函数参数中解析 [] 的格式通常是 [frist & rest]"));
    }

    /**
     * 解析函数几种输入参数
     * 1、[a b c]
     * 2、[a b & c]
     * 3、[a b [c & d]]
     * */
    fn to_func_param(lst: &Vec<Rc<CljCell>>) -> Vec<Rc<CljFuncParam>> {
        let mut rs: Vec<Rc<CljFuncParam>> = Vec::new();
        let mut flag = false;
        for i in 0..lst.len() {
            if flag == false {
                let c: Option<&Rc<CljCell>> = lst.get(i);
                let c1: Rc<CljCell> = c.unwrap().clone();
                match &*c1 {
                    CljCell::Symbol(fun_param) => {
                        rs.push(Rc::new(CljFuncParam::new((*fun_param).to_string())));
                    },
                    CljCell::Percent(vs) => {
                        let pv = vs.as_ref().unwrap();
                        rs.push(Rc::new(CljFuncParam::new((*pv).to_string())));
                    },
                    CljCell::AndClj => {
                        if i == lst.len() - 2 {
                            let mut clj_func_param = CljFuncParam::new1();
                            let s1 = lst.get(1 + i).unwrap();
                            clj_func_param.set_rest_param(s1.to_string());
                            rs.push(Rc::new(clj_func_param));
                            flag = true;
                        }
                    },
                    CljCell::BracketClj(lst) => {
                        //let cljFuncParamLists = CljFunctions::to_func_param_list(lst);
                        let mut clj_func_param = CljFuncParam::new1();
                        clj_func_param.set_clj_func_param_list(CljFunctions::to_func_param_list(&lst).unwrap());
                        rs.push(Rc::new(clj_func_param));
                    },
                    _ => return rs,
                }
            }
        }
        return rs;
    }

    fn to_param_body(fname: String, param_body: &[Rc<CljCell>]/*&Vec<Rc<CljCell>>*/) -> Result<CljFunc, String> {
        let fb:&Rc<CljCell> = &param_body[0];
        // 如果是 [a b] 这种类型
        if let CljCell::BracketClj(vs) = &**fb {
            // 函数参数
            let func_params: Vec<Rc<CljFuncParam>> = CljFunctions::to_func_param(vs);
            let lst_body: &[Rc<CljCell>] = &param_body[1..];
            if !lst_body.is_empty() {
                // 将函数存储到 funcs 列表
                return Ok(CljFunc::new(func_params, lst_body[0].clone()));
            }
        }
        let mut s = String::from(fname);
        s.push_str(" 输入参数的格式错误！");
        return Err(s);
    }

    pub fn to_param_body_1(param_body: &[Rc<CljCell>]) -> Result<CljFunc, String> {
        let fb:&Rc<CljCell> = &param_body[0];
        // 如果是 [a b] 这种类型
        if let CljCell::BracketClj(vs) = &**fb {
            // 函数参数
            let func_params: Vec<Rc<CljFuncParam>> = CljFunctions::to_func_param(vs);
            let lst_body: &[Rc<CljCell>] = &param_body[1..];
            if !lst_body.is_empty() {
                // 将函数存储到 funcs 列表
                return Ok(CljFunc::new(func_params, lst_body[0].clone()));
            }
        }
        let mut s = String::new();
        s.push_str("输入参数的格式错误！");
        return Err(s);
    }

    pub fn clj_list_defn(interp: &MyClojureInterp, lst: &Vec<Rc<CljCell>>, func_hs: &MyFuncHs, clj_recur: &MyCljRecur, rs: Rc<CljCell>) -> Rc<CljCell> {
        let f1:Option<&Rc<CljCell>> = lst.get(1);
        if f1.is_some() {
            let f: &Rc<CljCell> = Rc::try_unwrap(f1.unwrap().into()).unwrap();
            let f1: &CljCell = &**f;
            // 函数名
            if let CljCell::Symbol(fname) = f1 {
                let cell_list = &lst[2..];

                if cell_list.len() == 2 && my_util::is_bracket(&cell_list[0]) && my_util::is_clj_list(&cell_list[1]) {
                    let func = CljFunctions::to_param_body(fname.to_string(), cell_list);
                    interp.set_vs(fname.to_string(), MyCljFunc::new(func.unwrap()));
                } else {
                    let my_fun = MyCljFuncWraps::new();
                    my_fun.set_is_override(true);
                    for c1 in cell_list {
                        let c2: Rc<CljCell> = c1.clone();
                        if let CljCell::CljList(ls) = &*c2 {
                            let func: Result<CljFunc, String> = CljFunctions::to_param_body(fname.to_string(), ls);

                            let _ = CljFunctions::add_to_func(interp,&my_fun, func.unwrap());
                        }
                    }

                    let p = my_fun.get_my_clj_func();
                    interp.set_vs(fname.to_string(), *p);
                }
            }
        }
        return Rc::new(CljCell::Null);
    }

    pub fn clj_list_defn_0(interp: &MyClojureInterp, lst: &Vec<Rc<CljCell>>, func_hs: &MyFuncHs, clj_recur: &MyCljRecur, rs: Rc<CljCell>) -> Rc<CljCell> {
        let f1:Option<&Rc<CljCell>> = lst.get(1);
        if f1.is_some() {
            let f: &Rc<CljCell> = Rc::try_unwrap(f1.unwrap().into()).unwrap();
            let f1: &CljCell = &**f;
            // 函数名
            if let CljCell::Symbol(fname) = f1 {
                let cell_list = &lst[2..];

                if cell_list.len() == 2 && my_util::is_bracket(&cell_list[0]) && my_util::is_clj_list(&cell_list[1]) {
                    let func = CljFunctions::to_param_body(fname.to_string(), cell_list);
                    interp.set_vs(fname.to_string(), MyCljFunc::new(func.unwrap()));
                } else {
                    let my_clj_func = Box::new(MyCljFunc::new1(true));
                    let ptr_fun = Box::into_raw(my_clj_func);
                    for c1 in cell_list {
                        let c2: Rc<CljCell> = c1.clone();
                        if let CljCell::CljList(ls) = &*c2 {
                            let func: Result<CljFunc, String> = CljFunctions::to_param_body(fname.to_string(), ls);
                            let _ = CljFunctions::add_to_func_0(interp,ptr_fun, func.unwrap());
                        }
                    }
                    unsafe {
                        let p = Box::from_raw(ptr_fun);
                        //(*(*interp).ptr).set_vs(fname.to_string(), *p);
                        interp.set_vs(fname.to_string(), *p);
                    }
                }
            }
        }
        return Rc::new(CljCell::Null);
    }

    pub fn add_to_func_ex(myfns: &MyCljFuncWraps, func: Result<CljFunc, String>) {
        let cf = func.as_ref().unwrap();
        if !myfns.get_func_override().contains_key(&(cf.get_func_params().len() as i32)) {
            let n = cf.get_func_params().len() as i32;
            myfns.get_func_override_put(n, func.unwrap());
        }
    }

    /**
     * 匿名函数
     * lst :  size = 3  (fn [a b] (+ a b))
     * */
    pub fn clj_list_fn_in(interp: &MyClojureInterp, lst: &Vec<Rc<CljCell>>, func_hs: &MyFuncHs, clj_recur: &MyCljRecur, rs: Rc<CljCell>) -> Box<MyCljFunc> {
        let cell_list = &lst[1..];
        if cell_list.len() == 2 && my_util::is_bracket_rc(cell_list[0].clone()) && my_util::is_clj_list_rc(cell_list[1].clone()) {
            let fc: Result<CljFunc, String> = CljFunctions::to_param_body_1(cell_list);
            return Box::new(MyCljFunc::new(fc.unwrap()));
        } else {
            let my_clj_func = MyCljFunc::new1(true);
            let myfns = MyCljFuncWraps::new1(my_clj_func);
            for c1 in cell_list {
                if let CljCell::CljList(vs) = &**c1 {
                    let func: Result<CljFunc, String> = CljFunctions::to_param_body_1(vs);
                    CljFunctions::add_to_func_ex(&myfns, func);
                }
            }
            return myfns.get_my_clj_func();
        }
    }

    /**
     * 匿名调用方法
     * */
    pub fn clj_list_fn(interp: &MyClojureInterp, lst: &Vec<Rc<CljCell>>, func_hs: &MyFuncHs, clj_recur: &MyCljRecur, rs: Rc<CljCell>) -> Rc<CljCell> {
        if let CljCell::CljList(lst_vs) = &*lst[0] {
            let my_clj_func: Box<MyCljFunc> = CljFunctions::clj_list_fn_in(interp, lst_vs, func_hs, clj_recur, rs.clone());
            let mut clj_func: &CljFunc = (*my_clj_func).get_clj_func();

            if *(*my_clj_func).get_is_override() {
                let ps_num = (lst.len() - 1) as i32;
                clj_func = (*my_clj_func).get_clj_func_1(ps_num).unwrap();
            }

            // 参数
            let clj_func_param_list: &Vec<Rc<CljFuncParam>> = clj_func.get_func_params();
            // 函数体
            let clj_cell_body: &Rc<CljCell> = clj_func.get_func_body();
            let ht: HashMap<String, Rc<CljCell>> = MyFunctions::get_params(clj_func_param_list, &lst[1..]);
            clj_recur.set_func_cell_body(clj_cell_body.clone());
            clj_recur.set_clj_func_param_list(clj_func_param_list.clone());

            for (k, v) in &ht {
                match &**v {
                    CljCell::CljList(lss) => {
                        func_hs.insert(k.to_string(), interp.clj_list(lss, func_hs, clj_recur, rs.clone()));
                    },
                    CljCell::Symbol(vs_name) => {
                    },
                    _ => {
                        func_hs.insert(k.to_string(), v.clone());
                    },
                }
                // if let CljCell::CljList(lss) = &**v {
                //     func_hs.insert(k.to_string(), interp.clj_list(lss, func_hs, CljRecur, rs.clone()));
                // } else {
                //     func_hs.insert(k.to_string(), v.clone());
                // }
            }

            return interp.eval(clj_cell_body, func_hs, clj_recur, rs.clone());
        }
        return Rc::new(CljCell::Null);
    }

    /**
     * 匿名调用方法
     * */
    pub fn clj_list_anonymous(interp: &MyClojureInterp, lst: &Vec<Rc<CljCell>>, func_hs: &MyFuncHs, clj_recur: &MyCljRecur, rs: Rc<CljCell>) -> Rc<CljCell> {
        if let CljCell::Anonymous(vs_lst) = &*lst[0] {
            if lst.len() >= 2 {
                let mut clj_func_param_list: Vec<Rc<CljFuncParam>> = Vec::new();
                for i in 1..lst.len() {
                    match &*lst[i] {
                        CljCell::CljList(lss) => {
                            func_hs.insert(i.to_string(), interp.clj_list(lss, func_hs, clj_recur, rs.clone()));
                        },
                        CljCell::Symbol(vs_name) => {
                        },
                        _ => {
                            func_hs.insert(i.to_string(), lst[i].clone());
                        },
                    }
                    // if let CljCell::CljList(lss) = &*lst[i] {
                    //     func_hs.insert(i.to_string(), interp.clj_list(lss, func_hs, CljRecur, rs.clone()));
                    // } else {
                    //     func_hs.insert(i.to_string(), lst[i].clone());
                    // }

                    clj_func_param_list.push(Rc::new(CljFuncParam::new(i.to_string())));
                }

                clj_recur.set_func_cell_body(lst[0].clone());
                clj_recur.set_clj_func_param_list(clj_func_param_list);

                return interp.clj_list(vs_lst, func_hs, clj_recur, rs.clone());
            }
        }

        return Rc::new(CljCell::Null);
    }
}

























































